/**
 * Created by Butterfly on 27.11.2012
 */
package com.lohika;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;


/**
 * @author Butterfly
 *
 */
public class BinaryProcessor extends HttpServlet {

	private static final long serialVersionUID = 1L;

	private static Logger LOG = Logger.getLogger(BinaryProcessor.class);
	
	private static final int DEFAULT_BUFFER_SIZE = 1024;
	
	private ConcurrentMap<ByteArrayWrapper, byte[]> cache = new ConcurrentHashMap<ByteArrayWrapper, byte[]>();
	
	/**
	 * This method puts incoming sorted array to map and returns this value.
	 * If the key with value exists the method returns value from map.
	 * @param input - existing array
	 */
	private byte[] put(ByteArrayWrapper input) {
		LOG.debug( "Starting calculation " );
		byte[] result = cache.get(input);
		if (result == null) {
			result = sortArray(input.getData());
			cache.putIfAbsent(input, result);
		}
		LOG.debug( "Done with calculation " );
		return result;
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {						    
		byte[] output = readData(req);
        put(new ByteArrayWrapper(output));
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		byte[] output = readData(req);
		byte[] bs = cache.get(new ByteArrayWrapper(output));
		resp.getOutputStream().write(bs);
		resp.getOutputStream().close();
	}
	
	
	/**
	 * Returns reading array of bytes
	 * @param request - HttpServletRequest
	 */
	private byte[] readData(HttpServletRequest request) throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int numBytesRead = 0;
        while (-1 != (numBytesRead = request.getInputStream().read(buffer))) {
            output.write(buffer, 0, numBytesRead);
        }
        output.close();
        output.flush();
        return output.toByteArray();
	}
	
	/**
	 * Returns sorted array of bytes in descending order
	 * @param input - existing array
	 */
	private byte[] sortArray(byte[] input) {
		LOG.debug( "Starting sorting array " );
		byte[] array = Arrays.copyOf( input, input.length );
		byte temp;
		for (int i = 0; i < array.length - 1; i++) {
			for (int j = i + 1; j < array.length; j++) {
				if (array[i] < array[j]) {
					temp = array[j];
					array[j] = array[i];
					array[i] = temp;
				}
			}
		}
		LOG.debug( "Done with sorting array " );
		return (array);
	}
}
